#include <iostream>
#include <vector>
#include <memory>
#include <functional>
#include <mysql/mysql.h>

class MySQLHelpper
{
    const std::string host = "127.0.0.1";
    const std::string user = "root";
    const std::string passwd = "zsw203526";
    const std::string database = "test";
    const int port = 3306;

public:
    MySQLHelpper()
    {
        _handler = mysql_init(nullptr);
    }

    bool connect()
    {
        if (mysql_real_connect(_handler, host.c_str(), user.c_str(), passwd.c_str(), database.c_str(), port, nullptr, 0) == nullptr)
        {
            std::cout << "连接数据库错误，错误原因：" << mysql_error(_handler) << std::endl;
            close();
            return false;
        }

        return true;
    }

    template <typename Func>
    bool excuteSQL(const std::string &sql, Func &&exec)
    {
        if (mysql_query(_handler, sql.c_str()) != 0)
        {
            std::cout << "执行sql语句" << sql << "失败，" << "失败原因：" << mysql_error(_handler) << std::endl;
            return false;
        }

            MYSQL_RES *result = mysql_store_result(_handler);
            if (result == nullptr)
            {
                std::cout << "查询语句获取结果集失败，失败原因：" << mysql_error(_handler) << std::endl;
                return false;
            }

            int num_fields = mysql_num_fields(result);
            MYSQL_ROW row;
            while ((row = mysql_fetch_row(result))) 
            {
                std::vector<std::string> row_v;
                for (int i = 0; i < num_fields; i++)
                {
                    if(row[i] != nullptr)
                        row_v.push_back(row[i]);
                    else 
                        row_v.push_back("");
                }
                std::forward<Func>(exec)(row_v);

            }
            mysql_free_result(result);
        return true;
    }

    bool excuteSQL(const std::string &sql)
    {
        if (mysql_query(_handler, sql.c_str()) != 0)
        {
            std::cout << "执行sql语句" << sql << "失败，" << "失败原因：" << mysql_error(_handler) << std::endl;
            // mysql_close(_handler);
            return false;
        }
        return true;
    }


    void close()
    {
        mysql_close(_handler);
    }

    ~MySQLHelpper()
    {
        close();
    }

private:
    MYSQL *_handler;
};

void func(const std::vector<std::string>& row, std::vector<std::vector<std::string>>& ret)
{
    // std::cout << "调用" << std::endl;
    ret.push_back(row);
}

int main()
{
    std::unique_ptr<MySQLHelpper> sql_helpper = std::make_unique<MySQLHelpper>();

    std::vector<std::vector<std::string>> ret;
    // auto func = [&ret](const std::vector<std::string>& row)
    // {
    //     ret.push_back(row);
    // };

    // const std::string insert_sql = "insert into myclass(class_num, class_name) value(5, '高三班');";
    // sql_helpper->connect();

    // sql_helpper->excuteSQL(insert_sql);

    sql_helpper->connect();

    const std::string select_sql = "select * from myclass;";
    sql_helpper->excuteSQL(select_sql, std::bind(&func, std::placeholders::_1, std::ref(ret)));

    for(auto& row : ret)
    {
        for(auto& col : row)
        {
            std::cout << col << " ";
        }
        std::cout << std::endl;
    }

    const std::string delete_sql = "delete from myclass where class_num=5;";

    sql_helpper->excuteSQL(delete_sql);

    // const std::string select_sql = "select * from myclass;";
    sql_helpper->excuteSQL(select_sql, std::bind(&func, std::placeholders::_1, std::ref(ret)));

    for(auto& row : ret)
    {
        for(auto& col : row)
        {
            std::cout << col << " ";
        }
        std::cout << std::endl;
    }

    // sql_helpper->close();
    return 0;
}